/*
 * 普耐认证此内容只能进行项目开发,不能作为商用.
 * 认证地址如下:
 *
 *      http://www.puna.com.cn/licenses/LICENSE-2.0
 */ 
package com.punai.externalccb.constants;

import com.punai.common.constant.Constants;
import org.apache.commons.compress.archivers.zip.*;
import org.apache.commons.compress.utils.IOUtils;

import java.io.*;
import java.util.Enumeration;

/**
 * 说明：Zip工具栏类，依赖于commons-compress-1.8.1jar。
 * @Title: ZipUtil.java 
 * @Package com.gtx.utac.filemanage.util 
 * @See: {@link #ZipUtil()}
 * Copyright: Copyright (c) 2014 
 * Company:puna team by product
 * @author: fuyp   
 * @date: 2015年10月22日 下午1:43:23 
 * @version: V1.0
 * update Release(文件修正记录)
 * <pre>
 * author--updateDate--description----------------------Flag————
 * fuyp    2014-5-1    测试XXXXX                        #fuyp001
 *
 * </pre>
 *
 */
public class ZipUtil {
	/**
     * 把N多文件或文件夹压缩成zip。
     * @param files   需要压缩的文件或文件夹。
     * @param zipFile 压缩后的zip文件
     */
    public static void compress(File[] files, File zipFile) throws IOException {
        if (files == null || files.length == 0) {
            return;
        }
        ZipArchiveOutputStream out = new ZipArchiveOutputStream(zipFile);
        out.setUseZip64(Zip64Mode.AsNeeded);
        // 将每个文件用ZipArchiveEntry封装
        for (File file : files) {
            if (file == null) {
                continue;
            }
            compressOneFile(file, out, "");
        }
        if (out != null) {
            out.close();
        }
    }
 
    /**
     * 功能：压缩文件或文件夹。
     * @param srcFile  源文件。
     * @param destFile 压缩后的文件
     */
    public static void compress(File srcFile, File destFile) throws Exception {
        ZipArchiveOutputStream out = null;
       try {
           out = new ZipArchiveOutputStream(new BufferedOutputStream(new FileOutputStream(destFile), 1024));
           compressOneFile(srcFile, out, "");
       } finally {
           out.close();
       }
    }
 
    /**
     * 功能：压缩单个文件,非文件夹。私有，不对外开放。
     * @param srcFile 源文件，不能是文件夹。
     * @param out     压缩文件的输出流。
     * @param dir     压缩后的文件
     * @param dir     在压缩包中的位置,根目录传入/。
     */
    private static void compressOneFile(File srcFile,
                                        ZipArchiveOutputStream out, String dir) throws IOException {
        if (srcFile.isDirectory()) {// 对文件夹进行处理。
            String[] subFiles = srcFile.list();
            if (subFiles == null || subFiles.length < 1) {
            	// 为空目录、创建一个压缩包。
                ZipArchiveEntry entry = new ZipArchiveEntry(srcFile, dir + srcFile.getName());
                out.putArchiveEntry(entry);
                out.closeArchiveEntry();
                return;
            }
            for (String subFile : subFiles) {
                compressOneFile(new File(srcFile.getPath() + Constants.FILE_SEP + subFile),
                        out, (dir + srcFile.getName() + Constants.FILE_SEP));
            }
        } else { // 普通文件。
            InputStream is = null;
            try {
                is = new BufferedInputStream(new FileInputStream(srcFile));
                // 创建一个压缩包。
                ZipArchiveEntry entry = new ZipArchiveEntry(srcFile, dir + srcFile.getName());
                out.putArchiveEntry(entry);
                IOUtils.copy(is, out);
                out.closeArchiveEntry();
            } finally {
                if (is != null)
                    is.close();
            }
        }
    }
    /**
     * 
     * 说明：解压缩zip流压缩包下的所有文件。
     * @Title: decompressZip
     * @See: {@link #decompressZip(InputStream, String)}
     * @author fuyp 
     * @param inputStream zip流压缩包
     * @param dir 解压缩到这个路径下
     * @throws IOException 
     * @date: 2015年10月22日 下午4:01:42
     */
    public static void decompressZip(InputStream inputStream, String dir) throws IOException {
    	ZipArchiveInputStream zipArchiveIs = new ZipArchiveInputStream(inputStream,"GBK");
    	try {
    		ZipArchiveEntry ze = null;
    		while((ze = zipArchiveIs.getNextZipEntry()) != null){
                // 不存在则创建目标文件夹。
                File targetFile = new File(dir, ze.getName());
                // 遇到根目录时跳过。
                if (ze.getName().lastIndexOf(Constants.FILE_SEP) == (ze.getName().length() - 1)) {
                    continue;
                }
                if (ze.isDirectory()){
                	// 如果文件夹不存在，创建文件夹。
                    if (!targetFile.exists()) {
                        targetFile.mkdirs();
                    }
                	continue;
                }
                // 如果文件夹不存在，创建文件夹。
                if (!targetFile.getParentFile().exists()) {
                    targetFile.getParentFile().mkdirs();
                }

                OutputStream o = null;
                try {
                    o = new FileOutputStream(targetFile);
                    IOUtils.copy(zipArchiveIs, o);
                } finally {
                    if (o != null) {
                    	IOUtils.closeQuietly(o);
                    }
                }
            }
        } finally {
        	zipArchiveIs.close();
        }
    }
 
    /**
     * 功能：解压缩zip压缩包下的所有文件。
     * @param zipFile zip压缩文件
     * @param dir     解压缩到这个路径下
     */
    public static void decompressZip(File zipFile, String dir) throws IOException {
        ZipFile zf = new ZipFile(zipFile,"GBK");
        try {
            for (Enumeration<ZipArchiveEntry> entries = zf.getEntries(); entries.hasMoreElements(); ) {
                ZipArchiveEntry ze = entries.nextElement();
                // 不存在则创建目标文件夹。
                File targetFile = new File(dir, ze.getName());
                // 遇到根目录时跳过。
                if (ze.getName().lastIndexOf(Constants.FILE_SEP) == (ze.getName().length() - 1)) {
                    continue;
                }
                if (ze.isDirectory()){
                	// 如果文件夹不存在，创建文件夹。
                    if (!targetFile.exists()) {
                        targetFile.mkdirs();
                    }
                	continue;
                }
                // 如果文件夹不存在，创建文件夹。
                if (!targetFile.getParentFile().exists()) {
                    targetFile.getParentFile().mkdirs();
                }
               
                InputStream i = zf.getInputStream(ze);
                OutputStream o = null;
                try {
                    o = new FileOutputStream(targetFile);
                    IOUtils.copy(i, o);
                } finally {
                    if (i != null) {
                        i.close();
                    }
                    if (o != null) {
                        o.close();
                    }
                }
            }
        } finally {
            zf.close();
        }
    }
 
    /**
     * 功能：解压缩zip压缩包下的某个文件信息。
     * @param zipFile  zip压缩文件
     * @param fileName 某个文件名,例如abc.zip下面的a.jpg，需要传入/abc/a.jpg。
     * @param dir      解压缩到这个路径下
     */
    public static void decompressZip(File zipFile, String fileName, String dir)
            throws IOException {
        // 不存在则创建目标文件夹。
        File targetFile = new File(dir, fileName);
        if (!targetFile.getParentFile().exists()) {
            targetFile.getParentFile().mkdirs();
        }
 
        ZipFile zf = new ZipFile(zipFile);
        Enumeration<ZipArchiveEntry> zips = zf.getEntries();
        ZipArchiveEntry zip = null;
        while (zips.hasMoreElements()) {
            zip = zips.nextElement();
            if (fileName.equals(zip.getName())) {
                OutputStream o = null;
                InputStream i = zf.getInputStream(zip);
                try {
                    o = new FileOutputStream(targetFile);
                    IOUtils.copy(i, o);
                } finally {
                    if (i != null) {
                        i.close();
                    }
                    if (o != null) {
                        o.close();
                    }
                    if (zf != null) {
                    	zf.close();
                    }
                }
            }
        }
    }
 
    /**
     * 功能：得到zip压缩包下的某个文件信息,只能在根目录下查找。
     * @param zipFile  zip压缩文件
     * @param fileName 某个文件名,例如abc.zip下面的a.jpg，需要传入/abc/a.jpg。
     * @return ZipArchiveEntry 压缩文件中的这个文件,没有找到返回null。
     */
    public static ZipArchiveEntry readZip(File zipFile, String fileName)
            throws IOException {
        ZipFile zf = new ZipFile(zipFile);
        Enumeration<ZipArchiveEntry> zips = zf.getEntries();
        ZipArchiveEntry zip = null;
        while (zips.hasMoreElements()) {
            zip = zips.nextElement();
            if (fileName.equals(zip.getName())) {
                return zip;
            }
        }
        return null;
    }
 
    /**
     * 功能：得到zip压缩包下的所有文件信息。
     * @param zipFile zip压缩文件
     * @return Enumeration<ZipArchiveEntry> 压缩文件中的文件枚举。
     */
    public static Enumeration<ZipArchiveEntry> readZip(File zipFile)
            throws IOException {
        ZipFile zf = new ZipFile(zipFile);
        Enumeration<ZipArchiveEntry> zips = zf.getEntries();
        return zips;
    }
    
    
    
    /**
     * 解压文件到指定目录
     * @param zipFile
     * @param descDir
     * @author isea533
     */ 
    @SuppressWarnings("rawtypes") 
    public static void unZipFiles(File zipFile,String descDir)throws IOException{ 
		File pathFile = new File(descDir);
		if (!pathFile.exists()) {
			pathFile.mkdirs();
		}
		ZipFile zip = new ZipFile(zipFile);
		for (Enumeration entries = zip.getEntries(); entries.hasMoreElements();) {
			ZipArchiveEntry entry = (ZipArchiveEntry) entries.nextElement();
			String zipEntryName = entry.getName();
			InputStream in = zip.getInputStream(entry);
			String outPath = (descDir + zipEntryName).replaceAll("\\*", Constants.FILE_SEP);
			
			// 判断路径是否存在,不存在则创建文件路径
			File file = new File(outPath.substring(0, outPath.lastIndexOf(Constants.FILE_SEP)));
			if (!file.exists()) {
				file.mkdirs();
			}
			// 判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
			if (new File(outPath).isDirectory()) {
				continue;
			}

			OutputStream out = new FileOutputStream(outPath);
			byte[] buf1 = new byte[1024];
			int len;
			while ((len = in.read(buf1)) > 0) {
				out.write(buf1, 0, len);
			}
			in.close();
			out.close();
		}
    }
    
    
    /**
     * 解压qdz时 对其进行偏移 操作, 偏移量: 256 + 50 * 1024 + 268
     * 
     */
    public static void decompressZipOfSet(InputStream inputStream, String dir) throws IOException {
		//	inputStream
		BufferedInputStream is = new BufferedInputStream(inputStream);
		is.skip(256 + 50 * 1024 + 268);
    	decompressZip2(is,dir);
    }
    
    
    public static void decompressZip2(InputStream inputStream, String dir) throws IOException {
    	ZipArchiveInputStream zipArchiveIs = new ZipArchiveInputStream(inputStream,"GBK");
    	try {
    		while(zipArchiveIs.getNextZipEntry() != null){

                File targetFile = new File(dir);

                OutputStream o = null;
                try {
                    o = new FileOutputStream(targetFile);
                    IOUtils.copy(zipArchiveIs, o);
                } finally {
                    if (o != null) {
                    	IOUtils.closeQuietly(o);
                    }
                }
            }
        } finally {
        	zipArchiveIs.close();
        }
    }
    
    
//    public static void main(String[] args) {
////    	File zipFile = new File("D:\\翻译文档.zip");
////		try {
////			ZipUtil.unZipFiles(zipFile, "D:\\GGWork\\temp\\");
////		} catch (IOException e) {
////			// TODO Auto-generated catch block
////			e.printStackTrace();
////		}
//	}
}
